﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
    using Emgu.CV;
    using Emgu.CV.CvEnum;
    using Emgu.CV.Structure;
    using Emgu.CV.Util;
    using System.Drawing;
namespace WinFormsApp1
{


    public class PuzzleIconDetector
    {
        /// <summary>
        /// 检测与背景有色差的拼图边框
        /// </summary>
        public static List<Rectangle> DetectContrastBorder(string imagePath)
        {
            using (Mat src = CvInvoke.Imread(imagePath, ImreadModes.Color))
            {
                if (src.IsEmpty) throw new ArgumentException("无法加载图像");

                // 1. 聚焦右下1/4区域
                Rectangle searchROI = GetSearchROI(src);

                using (Mat roi = new Mat(src, searchROI))
                {
                    // 2. 转换到LAB颜色空间
                    Mat lab = new Mat();
                    CvInvoke.CvtColor(roi, lab, ColorConversion.Bgr2Lab);

                    // 3. 动态颜色差异检测
                    Mat diffMap = CalculateColorDiff(lab);

                    // 4. 自适应二值化
                    Mat binary = new Mat();
                    CvInvoke.Threshold(diffMap, binary, 0, 255,
                        ThresholdType.Binary | ThresholdType.Otsu);

                    // 5. 形态学优化
                    Mat kernel = CvInvoke.GetStructuringElement(
                        ElementShape.Cross,
                        new Size(5, 5),    // 结构元素尺寸
                        new Point(-1, -1)  // 必须添加锚点参数
                    );

                    CvInvoke.MorphologyEx(
                        binary,            // 输入图像
                        binary,            // 输出图像
                        MorphOp.Close,     // 操作类型
                        kernel,            // 结构元素
                        new Point(-1, -1), // 锚点（默认中心）
                        3,                 // 迭代次数
                        BorderType.Replicate, // 边界类型101
                        new MCvScalar(0)   // 边界值
                    );

                    // 6. 轮廓检测与分析
                    VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
                    CvInvoke.FindContours(binary, contours, null, RetrType.List,
                        ChainApproxMethod.ChainApproxSimple);
                    List<Rectangle> results = new List<Rectangle>();
                    for (int i = 0; i < contours.Size; i++)
                    {
                        using (VectorOfPoint contour = contours[i])
                        {
                            Rectangle rect = ValidateContour(contour, searchROI, src);
                            if (rect != Rectangle.Empty) 
                                results.Add(rect);
                        }
                    }
                    return results;
                }
                return null;
            }
        }

        /// <summary>
        /// 计算颜色差异图（LAB空间）
        /// </summary>
        private static Mat CalculateColorDiff(Mat lab)
        {
            Mat[] channels = lab.Split();
            Mat diff = new Mat();

            // 计算色度差异（A、B通道）
            CvInvoke.AbsDiff(channels[1], channels[2], diff);
            CvInvoke.Normalize(diff, diff, 0, 255, NormType.MinMax);

            // 增强亮度对比（L通道）
            CvInvoke.AddWeighted(diff, 0.7, channels[0], 0.3, 0, diff);

            channels.ToList().ForEach(m => m.Dispose());
            return diff;
        }

        /// <summary>
        /// 验证轮廓有效性
        /// </summary>
        private static Rectangle ValidateContour(VectorOfPoint contour, Rectangle searchROI, Mat src)
        {
        
            if (CvInvoke.ContourArea(contour) < 10) return Rectangle.Empty;

            Rectangle rect = CvInvoke.BoundingRectangle(contour);
            rect.Offset(searchROI.X, searchROI.Y);

            // 内外颜色差异验证
            using (Mat mask = CreateBorderMask(src, rect))
            {
                var inner = CvInvoke.Mean(src, mask);
                var outer = CvInvoke.Mean(src, 255 - mask);

                double colorDiff = CalculateColorDistance(inner, outer);
                if (colorDiff < 30) return Rectangle.Empty;
            }

            // 形状验证
          //  if (!IsValidShape(contour)) return Rectangle.Empty;

            return rect;
        }

        /// <summary>
        /// 创建边框区域mask
        /// </summary>
        private static Mat CreateBorderMask(Mat src, Rectangle rect)
        {
            Mat mask = new Mat(src.Size, DepthType.Cv8U, 1);
            mask.SetTo(new MCvScalar(0));

            int borderWidth = Math.Max(3, rect.Width / 10);
            Rectangle borderRect = new Rectangle(
                rect.X + borderWidth,
                rect.Y + borderWidth,
                rect.Width - 2 * borderWidth,
                rect.Height - 2 * borderWidth);

            CvInvoke.Rectangle(mask, borderRect, new MCvScalar(255), -1);
            return mask;
        }

        /// <summary>
        /// 计算颜色差异（欧氏距离）
        /// </summary>
        private static double CalculateColorDistance( MCvScalar c1, MCvScalar c2)
        {
            double bDiff = c1.V0 - c2.V0;
            double gDiff = c1.V1 - c2.V1;
            double rDiff = c1.V2 - c2.V2;
            return Math.Sqrt(bDiff * bDiff + gDiff * gDiff + rDiff * rDiff);
        }

        /// <summary>
        /// 形状验证（长宽比+复杂度）
        /// </summary>
        private static bool IsValidShape(VectorOfPoint contour)
        {
            Rectangle rect = CvInvoke.BoundingRectangle(contour);
            float aspect = rect.Width / (float)rect.Height;
            if (aspect < 0.8 || aspect > 1.2) return false;

            double perimeter = CvInvoke.ArcLength(contour, true);
            double area = CvInvoke.ContourArea(contour);
            return (4 * Math.PI * area) / (perimeter * perimeter) > 0.65;
        }

        private static Rectangle GetSearchROI(Mat src)
        {
            return new Rectangle(0,0,src.Width,src.Height);
                //src.Width * 3 / 4,
                //src.Height * 3 / 4,
                //Math.Max(100, src.Width / 4),
                //Math.Max(100, src.Height / 4));
        }

        /// <summary>
        /// 可视化检测结果
        /// </summary>
        public static void VisualizeResult(string inputPath, string outputPath, List<Rectangle> borders)
        {
            using (Mat src = CvInvoke.Imread(inputPath))
            {
                foreach (var rect in borders)
                {
                    CvInvoke.Rectangle(src, rect, new MCvScalar(0, 255, 0), 3);
                }
                CvInvoke.Imwrite(outputPath, src);
            }
        }
        // 使用示例
        public static List<Rectangle> Main5(string b)
        {
            try
            {
                string input = b; 
                string output = "output_" + b;
                var result = DetectContrastBorder(input);

                if (result.Count>0)
                {
                    Console.WriteLine($"检测成功！");
                    var borders = result;
                    VisualizeResult(input, output, borders);
                    return borders;
                }
                else
                {
                    Console.WriteLine("未找到拼图图标");
                }
              
            }
            catch (Exception ex)
            {
                Console.WriteLine($"错误：{ex.Message}");
            }
            return new List<Rectangle>();
        }
    }
}
